package com.example.springsecurity.demo.config;

import com.example.springsecurity.demo.handle.MyAccessDeniedHandler;
import com.example.springsecurity.demo.handle.MyAuthenticationFailureHandler;
import com.example.springsecurity.demo.service.UserDetailServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;


@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder getPw(){
        return new BCryptPasswordEncoder();
    }

    @Autowired
    private MyAccessDeniedHandler myAccessDeniedHandler;   //自定义403

    @Lazy  //防止依赖循环
    @Autowired
    private UserDetailServiceImpl userDetailService;

    @Autowired
    private DataSource dataSource;

    @Lazy  //防止依赖循环
    @Autowired
    private PersistentTokenRepository persistentTokenRepository;

    @Bean
    public PersistentTokenRepository getPersistentTokenRepository(){
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        //自动键表, 第一次启动的时候需要, 第二次启动需要注释
        //jdbcTokenRepository.setCreateTableOnStartup(true);
        return jdbcTokenRepository;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.formLogin()
                .loginPage("/login.html")  //自定义登录页面
                .loginProcessingUrl("/login")  //  参数/login 是表单提交跳转的地址, 当发现是/login时,认为是登录 去执行UserDetailServiceImpl
                .successForwardUrl("/toMain")  //登录成功后跳转页面 必须是post请求
                //.successHandler(new MyAuthenticationSuccessHandle("http://www.baidu.com")) // 跨域跳转 不可以和successForwardUrl()方法同时存在
                //.failureForwardUrl("/toError")
                .failureHandler(new MyAuthenticationFailureHandler("https://cn.bing.com")) // 跨域跳转 不可以和failureForwardUrl()方法同时存在
                .usernameParameter("username")
                .passwordParameter("password");  //登录失败后跳转 也必须是post请求

        http.authorizeRequests()
                .antMatchers("/login.html").permitAll()   //login.html不需要被认证
                .antMatchers("/error.html").permitAll()   //login.html不需要被认证
                .antMatchers("/demo").permitAll()   //login.html不需要被认证
                .antMatchers("/js/**", "/css/**").permitAll()
                //.antMatchers("/home.html").hasRole("adminn")
                //.anyRequest().access("@myServiceImpl.hasPermission(request, authentication)");
                .anyRequest().authenticated();  //所有请求都必须认证才能访问  除了上面antMatchers的

        //自定义403
        http.exceptionHandling()
                .accessDeniedHandler(myAccessDeniedHandler);

        http.rememberMe()
                //设置失效事件, 默认是14天
                .tokenValiditySeconds(60)   //设置为1分钟
                //.rememberMeParameter("rememberMe")   //修改前端的input 的checkbox的name属性值
                //自定义登录逻辑
                .userDetailsService(userDetailService)
                //持久层对象
                .tokenRepository(persistentTokenRepository);

        http.logout()
                //退出登录跳转页面
                .logoutSuccessUrl("/login.html");

        http.csrf().disable();  //关闭csrf防护
    }
}